package structure;

import java.util.ArrayList;

import javax.sound.midi.spi.MidiFileWriter;

import algorithm.miscellaneous;
import algorithm.utility;

public class production implements Cloneable{
	
	private
		String leftSide, allProduction;
		ArrayList<String> rightSide;
		ArrayList<String> lower;
		ArrayList<String> upper;
		
		//costruttori
	public production(){
		
		this.leftSide= "";
		this.allProduction= "";
		this.rightSide= new ArrayList<String>();
		this.lower= new ArrayList<String>();
		this.upper= new ArrayList<String>();
	}
		
	public	production(String paramP){
		/*
		 * una produzione è fatta cosi S->a|BC senza spazi
		 * il primo simbolo sarà il leftSide gli altri simboli 
		 * verranno dopo "->"
		 */
		if(!paramP.equals("")){
			this.allProduction= paramP;
			String tmp= "";
			char tmpA= ' ';
			
			if(miscellaneous.isANumber(paramP.substring(1,2).charAt(0))){
				//caso A3->a
				this.leftSide= paramP.substring(0, 2);
				tmp= paramP.substring(4);
				tmpA= paramP.substring(0, 1).charAt(0);
			}
			else{
				//caso A->a
				this.leftSide= paramP.substring(0, 1);
				tmp= paramP.substring(3);
				//System.out.println("production - tmp= " + tmp);
			}
			
			this.lower= new ArrayList<String>();
			this.upper= new ArrayList<String>();
			this.upper.add(this.leftSide);
			this.rightSide= new ArrayList<String>();
			
			char[] simbols= tmp.toCharArray();
			int start= 0, end= 0;
			
			//riempio i due array di simboli non terminali e terminali
			for(int i=0; i<simbols.length; i++){
				
				if(simbols[i] == '|'){
					
					end= i;
					String tmpS= tmp.substring(start, end);
					start= i+1;
	
					this.rightSide.add(tmpS);
					
					if(tmpS.length() < 2){
						
						char tmpC= tmpS.charAt(0);
						if(Character.isUpperCase(tmpC) && !(this.upper.contains(tmpS)) &&
								tmpC != tmpA) {
	
							this.upper.add(tmpS);
						}
						else if(!Character.isUpperCase(tmpC) && !(this.lower.contains(tmpS))
								&& !miscellaneous.isANumber(tmpC)) {// && !tmpS.equals("e")
							
							
							this.lower.add(tmpS);
						}
					}
					else{
						
						char[] tmpChar= tmpS.toCharArray();
						
						if(tmpChar.length == 2 && miscellaneous.isANumber(tmpChar[1])){
							
							this.upper.add(Character.toString(tmpChar[0]) + Character.toString(tmpChar[1]));
							tmpA= tmpChar[0];
						}
						else{
							for(char c : tmpChar){
							
								if(Character.isUpperCase(c) && !(this.upper.contains(Character.toString(c))) &&
										c != tmpA) {
			
									this.upper.add(Character.toString(c));
								}
								else if(!Character.isUpperCase(c) && !(this.lower.contains(Character.toString(c))) && 
										c != 'e' && !miscellaneous.isANumber(c)) {
									
									this.lower.add(Character.toString(c));
								}
							}
						}
	
					}
	
				}
				else{
				}
			}
		}
		else{
			System.out.println("String passata vuota, impossibile creare produzione.");
		}
		
		/*for (char c : simbols){
			
			if(c != '|'){
				
				tmpRight+= Character.toString(c);
				
				if(Character.isUpperCase(c) && !(this.upper.contains(Character.toString(c)))) {

					this.upper.add(Character.toString(c));
				}
				else if(!Character.isUpperCase(c) && !(this.lower.contains(Character.toString(c))) && c != 'e') {
					
					this.lower.add(Character.toString(c));
				}
			}
			else{
				
				this.rightSide.add(tmpRight);
				tmpRight= "";
			}
		}*/
	
	}
	//
	
	//get
	public	ArrayList<String> getUpper(){
			
		return this.upper;
	}
		
	public	ArrayList<String> getLower(){
			
		return this.lower;
	}
	
	public ArrayList<String> getRightSide(){
		
		return this.rightSide;
	}
	
	public String getLeftSide(){
		
		return this.leftSide;
	}
	
	//restituisce l'ordine di una produzione
	public ArrayList<Integer> getProductionOrders(){
		/*
		 * l'ordine di una produzione u->v è il max(|u|,|v|)
		 */
		int leftsideOrder= this.getLeftSide().length();
		ArrayList<String> rightside= this.getRightSide();
		ArrayList<Integer> toReturn= new ArrayList<Integer>();
		
		for(String s : rightside){
			
			toReturn.add(miscellaneous.getMax(leftsideOrder, s.length()));
		}
		
		return toReturn;
	}
	
	public int getProductionOrder(int production){
		
		return this.getProductionOrders().get(production);
	}
	
	public int getIndexOfProduction(String s){
		
		String rightside= s.substring(2);
		for(int i=0; i<this.rightSide.size(); i++){
			
			if(rightside.equals(this.rightSide.get(i))) 
				return i;
		}
		
		return -1;
	}
	//--------------------------------------------------------------------------------------
	
	//set
	public void setRightSide(ArrayList<String> rightside){
		
		this.rightSide.clear();
		this.rightSide.addAll(rightside);
		this.setAllProduction();
	}
	
	public void addRightSide(ArrayList<String> rightside){
		
		this.rightSide.addAll(rightside);
		this.setAllProduction();
	}
	
	public void setAllProduction(){
		
		this.allProduction= this.leftSide + "->";
		
		for(String s : this.rightSide){
			
			this.allProduction+= s + "|";
		}
	}
	
	public void setLeftside(String s){
		
		this.leftSide= s;
	}
	//--------------------------------------------------------------------------------------
	
	public void addProduction(String production){
		
		this.rightSide.add(production);
	}
	
	public String removeProductionByIndex(int productionIndex){
		
		return this.rightSide.remove(productionIndex);
	}
	
	//rimuove dal rightside la produzione passata come parametro
	public String removeProductionByString(String productionString){
		
		String toReturn= "";
		for(int i=0; i<this.rightSide.size(); i++){
			
			if(productionString.equals(this.rightSide.get(i))){
				
				toReturn= this.removeProductionByIndex(i);
				break;
			}
		}
		
		return toReturn;
	}
	
	public production clone() throws CloneNotSupportedException{
		
		production p= new production();
		p.leftSide= new String(this.leftSide);
		p.rightSide= (ArrayList<String>) this.rightSide.clone();
		p.lower= (ArrayList<String>) this.lower.clone();
		p.upper= (ArrayList<String>) this.upper.clone();
		return p;
	}
	
	public boolean contain(String s){
		
		return this.rightSide.contains(s);
	}
	
	public	void printIt(){

		System.out.println(this.allProduction);
		//this.printRightside();
	}
	
	public void printItAll(){
		
		System.out.println(this.leftSide + "-->" + this.rightSide.get(0));
	}
	
	public void printRightside(){
		
		System.out.print("rightside= ");
		for(String s : this.rightSide){
			
			System.out.print(s + "|");
		}
		
		System.out.println("");
	}

}
